<?php
namespace app\admin\controller;

use app\common\service\Upload;
use app\admin\service\Auth;
use app\common\model\MediaFile;
use think\Request;
use think\Image;

/**
 * 这个控制器主要负责 js文本控制器 的 接口/上传 等操作.
 */
class TextEditor extends BaseController
{
    /**
     * ueditor 需要用到的 返回配置 json.
     * @return array
     */
    protected function getUeditorConfig()
    {
        $config = config('ueditor.upload');
        return $config;
    }

    /**
     * ueditor 需要用到的 列出图片.
     * @param array $uploadConfig 配置
     * @param Request $request
     * @return array
     */
    protected function listImage($uploadConfig, Request $request)
    {
        $state = 'SUCCESS';
        $start = $request->param('start');
        $size = $request->param('size');
        $pagintor = MediaFile::fileExt($uploadConfig['imageAllowFiles'])
            ->order('id', 'desc')->paginate($size, false, ['page' => $start/$size + 1]);
        // 文件列表
        $list = array_map(function($img){
            return ['url' => $img->getFileUrl()];
        }, $pagintor->items());
        $total = $pagintor->total();
        return compact('state', 'list', 'start', 'total');
    }

    /**
     * ueditor 需要用到的 列出文件.
     * @param array $uploadConfig 配置
     * @param Request $request
     * @return array
     */
    protected function listFile($uploadConfig, Request $request)
    {
        $state = 'SUCCESS';
        $start = $request->param('start');
        $size = $request->param('size');
        $pagintor = MediaFile::fileExt($uploadConfig['fileAllowFiles'])
            ->order('id', 'desc')->paginate($size, false, ['page' => $start/$size + 1]);
        // 文件列表
        $list = array_map(function($img){
            return ['url' => $img->getFileUrl()];
        }, $pagintor->items());
        $total = $pagintor->total();
        return compact('state', 'list', 'start', 'total');
    }

    /**
     * ueditor 需要用到的 上传图片.
     * @param array $uploadConfig 配置
     * @return array
     */
    protected function uploadImage($uploadConfig)
    {
        $field = $uploadConfig['imageFieldName'];
        $options = [
            'size' => $uploadConfig['imageMaxSize'],
            'ext' => $uploadConfig['imageAllowFiles'],
            'file_category' => 'images'
        ];
        $upload = new Upload($options);
        $upload->setUploader(Auth::admin());
        $file = $upload->handle($field);
        return [
            "state" => 'SUCCESS', // 成功时, state 返回 'SUCCESS', 否则返回错误信息
            "url" => $file->getFileUrl(),
            "title" => $file->name,
            "original" => $file->name,
        ];
    }

    /**
     * ueditor 需要用到的 上传文件.
     * @param array $uploadConfig 配置
     * @return array
     */
    protected function uploadFile($uploadConfig)
    {
        $field = $uploadConfig['fileFieldName'];
        $options = [
            'size' => $uploadConfig['fileMaxSize'],
            'ext' => $uploadConfig['fileAllowFiles'],
            'file_category' => 'files'
        ];
        $upload = new Upload($options);
        $upload->setUploader(Auth::admin());
        $file = $upload->handle($field);
        return [
            "state" => 'SUCCESS', // 成功时, state 返回 'SUCCESS', 否则返回错误信息
            "url" => $file->getFileUrl(),
            "title" => $file->name,
            "original" => $file->name,
        ];
    }

    /**
     * ueditor 需要用到的 抓取远程图片.
     * 内部会检查文件大小, 当文件超过设置的上限时, 会进行压缩.
     * @param array $uploadConfig 配置
     * @param Request $request
     * @return array
     */
    protected function fetchRemoteImage($uploadConfig, Request $request)
    {
        $field = $uploadConfig['catcherFieldName'];
        $urls = $request->param($field);
        $imgs = [];
        try {
            foreach ($urls as $url) {
                $image = $this->downloadImage($uploadConfig, $url);
                $imgs[] = [
                    "url" => $image->getFileUrl(true),
                    "source" =>  $url,
                    "state" => "SUCCESS"
                ];
            }
            return [
                "state" => "SUCCESS",
                "list" => $imgs
            ];
        } catch (\Exception $e) {
            return ['state' => '操作失败!'];
        }
    }

    /**
     * 下载远程图片.
     * 内部会检查文件大小, 当文件超过设置的上限时, 会进行压缩.
     * @param array $uploadConfig 配置
     * @param string $url 图片地址
     * @return MediaFile
     */
    protected function downloadImage($uploadConfig, $url)
    {
        $img = curl_request($url);
        $md5 = md5($img);
        $root = env('upload_path');

        $dir = substr($md5, 0, 2);
        $filename = substr($md5, 2); // 首先用没有后缀的名称保存, 之后会 重命名 或 者压缩创建新文件(然后删除这个临时文件)
        $savedir = $root.'images/'.$dir;
        $tmpfile = $savedir.'/'.$filename;
        if (!is_dir($savedir)) {
            mkdir($savedir, 0755, true);
        }
        file_put_contents($tmpfile, $img);
        $admin_id = Auth::admin()->id;

        try {
            $image = Image::open($tmpfile);
            // type() 方法返回的不带 点号
            $ext = $image->type();
            $mime = $image->mime();
            $storage = 'local';
            $status = 1;
            $size = strlen($img);
            $savepath = $tmpfile.'.'.$ext;
            $path = 'images/'.$dir.'/'.$filename.'.'.$ext;
            $name = $md5.'.'.$ext;
            // 如果图片过大, 则压缩
            if ($size > $uploadConfig['catcherMaxSize']) {
                // 虽然这里调用的是 thumb, 但是是作为压缩来使用的...
                // 这个操作会覆盖已经存在的文件
                // 另外当原始图片的尺寸没有指定值大时, 不会生成缩略图...
                $image->thumb(1920, 1080)->save($savepath);
                unlink($tmpfile);
                $size = $image->size();
            } else {
                rename($tmpfile, $savepath);
            }

            $mediaFile = MediaFile::where('path', $path)->find();
            $data = compact('admin_id','name','md5', 'ext', 'mime', 'storage', 'status', 'size', 'path');
            if (!$mediaFile) {
                $mediaFile = new MediaFile();
                $mediaFile->data($data, true);
                $mediaFile->save();
            } else {
                $mediaFile->save($data);
            }
            return $mediaFile;

        } catch (\Exception $e) {
            // 出错时删除临时文件
            unlink($tmpfile);
            throw $e;
        }
    }

    public function ueditor(Request $request)
    {
        $uploadConfig = $this->getUeditorConfig();

        $action = $request->get('action');
        switch ($action) {
            case 'config':
                return json($uploadConfig);
                // lists
            case $uploadConfig['imageManagerActionName']: // 列出图片列表
                return json($this->listImage($uploadConfig, $request));
            case $uploadConfig['fileManagerActionName']: // 列出文件列表
                return json($this->listFile($uploadConfig, $request));
            case $uploadConfig['catcherActionName']: // 图片本地化
                // ueditor 可以把复制进来的外链图片下载到本地(本地化)
                return json($this->fetchRemoteImage($uploadConfig, $request));
            case $uploadConfig['imageActionName']: // 上传图片/上传截屏
                return json($this->uploadImage($uploadConfig));
            case $uploadConfig['fileActionName']: // 上传文件
            case $uploadConfig['videoActionName']: // 上传视频
                return json($this->uploadFile($uploadConfig));
            default:
                return json(['state' => '无效操作']);
        }
        return $this->fetch();
    }


    /**
     * 导入 word/excel 文档.
     */
    public function import_doc()
    {
        // 获取 word 文件信息
        $doc = $_FILES["file"];
        if (empty($doc['size'])) {
            $this->error('没有选择文档或文档上传失败(请注意文件大小是否超过服务器配置上限!)');
        }
        try {
            $parser = \app\common\service\Document\DocumentParserFactory::load($doc);
            // 解析 word 文档, 返回一个 ArticleDomain 对象
            $articleDomain = $parser->getArticle();
            $articleDomain->saveImagesInfo();
            return json(['html' => $articleDomain->content, 'code' => 1]);
        } catch (\Exception $e) {
            if(config('app_debug')) {
                $err = $e->getMessage()."\n".$e->getTraceAsString();
            }
            $this->error("导入失败! 请尝试用 wps 打开文件并重新导出为对应格式之后再导入.", null, $err, 10);
        } catch (\Error $e) {
            if(config('app_debug')) {
                $err = $e->getMessage()."\n".$e->getTraceAsString();
            }
            $this->error("导入失败! 请尝试用 wps 打开文件并重新导出为对应格式之后再导入.", null, $err, 10);
        }
    }

    /**
     * 解析在线视频的地址.
     */
    public function parse_video_url(Request $request)
    {
        $handlers = [
            ['match' => 'www.iqiyi.com', 'handler' => function($html) {
                preg_match("/param\[['\"]vid.*\"(.*)\"/", $html, $matches);
                $vid = $matches[1];
                preg_match("/param\[['\"]tvid.*\"(.*)\"/", $html, $matches);
                $tvid = $matches[1];
                return 'http://open.iqiyi.com/developer/player_js/coopPlayerIndex.html?vid='.$vid.'&tvId='.$tvid;
            }],
            ['match' => 'tv.sohu.com', 'handler' => function($html) {
                preg_match("/var\svid.*['\"](\d+)['\"]/", $html, $matches);
                $bid = $matches[1];
                return 'https://tv.sohu.com/s/sohuplayer/iplay.html?bid='.$bid.'&disablePlaylist=true';
            }]
        ];

        $url = $request->param('url');
        foreach ($handlers as $h) {
            if (strstr($url, $h['match'])) {
                $html = curl_request($url);
                return json(['src' => $h['handler']($html), 'code' => 1]);
            }
        }
    }
}
